package com.lzj.server.aspect;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.lzj.server.aspect.annotation.Submit;
import com.lzj.server.exceptions.BaseException;
import com.lzj.server.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;

import static com.lzj.server.constant.RedisConstant.SUBMIT_KEY_PREFIX;
@Slf4j
@Component
@Aspect
// 处理提交注解的切面类
public class SubmitAspect {

    // 定义切点，匹配带有@Submit注解的方法
    @Pointcut("@annotation(com.lzj.server.aspect.annotation.Submit)")
    public void pt() {}

    // 环绕通知，处理提交逻辑
    @Around("pt()")
    public Object around(ProceedingJoinPoint point) {
        Long userId = StpUtil.getLoginIdAsLong();
        String key = generateKey(userId, point);

        // 检查是否重复提交
        if (!isDuplicateSubmission(key)) {
           throw new BaseException("请勿重复提交");
        }

        try {
            // 执行目标方法
            Object result = point.proceed();
            // 设置缓存值
            saveToCache(key, result, point);
            return result;
        } catch (Throwable e) {
            log.error("处理提交时发生异常: {}", e.getMessage(), e);
            throw new BaseException("处理提交时发生异常");
        }
    }

    // 生成唯一的提交键
    private String generateKey(Long userId, ProceedingJoinPoint point) {
        Signature signature = point.getSignature();
        String className = point.getTarget().getClass().getSimpleName();
        String methodName = signature.getName();
        return SUBMIT_KEY_PREFIX + DigestUtil.md5Hex(userId + "::" + className + "::" + methodName);
    }

    // 检查是否为重复提交
    private boolean isDuplicateSubmission(String key) {
        Object value = RedisUtils.get(key);
        return Objects.isNull(value);
    }

    // 将结果保存到缓存中
    private void saveToCache(String key, Object result, ProceedingJoinPoint point) {
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        Submit annotation = method.getAnnotation(Submit.class);
        long time = annotation.time();
        RedisUtils.set(key, result, time);
    }
}
